﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FasterWPF
{
    //Credit to Sam Jackson for his Trampoline blog post and code here
    //http://blog.functionalfun.net/2008/04/bouncing-on-your-tail.html
    public static class Trampoline
    {
        public static Func<T1, TResult> MakeTrampoline<T1, TResult>(Func<T1, Bounce<T1, TResult>> function)
        {
            Func<T1, TResult> trampolined = (T1 arg1) =>
            {
                T1 currentArg1 = arg1;

                while (true)
                {
                    Bounce<T1, TResult> result = function(currentArg1);

                    if (result.HasResult)
                    {
                        return result.Result;
                    }
                    else
                    {
                        currentArg1 = result.Param1;
                    }
                }
            };
            return trampolined;
        }

        public static Bounce<T1, TResult> Recurse<T1, TResult>(T1 arg1)
        {
            return new Bounce<T1, TResult>(arg1);
        }

        public static Bounce<T1, TResult> ReturnResult<T1, TResult>(TResult result)
        {
            return new Bounce<T1, TResult>(result);
        }
    }

    public struct Bounce<T1, TResult>
    {
        public T1 Param1 { get; private set; }

        public TResult Result { get; private set; }

        public bool HasResult { get; private set; }

        public bool Recurse { get; private set; }

        public Bounce(T1 param1)
            : this()
        { Param1 = param1; HasResult = false; Recurse = true; }

        public Bounce(TResult result)
            : this()
        { Result = result; HasResult = true; Recurse = false; }
    }
}
